import 'reflect-metadata';
import { METADATA_KEYS, InjectableOptions, ServiceToken } from './types';

// 声明 Reflect 扩展
declare global {
    namespace Reflect {
        function defineMetadata(key: any, value: any, target: any): void;
        function getMetadata(key: any, target: any): any;
    }
}

// 确保 Reflect.metadata 支持
if (!(Reflect as any).defineMetadata) {
    require('reflect-metadata');
}

/**
 * 标记类为可注入的装饰器
 * @param options 注入选项
 */
export function Injectable(options: InjectableOptions = {}) {
    return function <T extends new (...args: any[]) => any>(constructor: T) {
        // 存储元数据
        Reflect.defineMetadata(METADATA_KEYS.INJECTABLE, {
            lifecycle: options.lifecycle || 'transient',
            token: options.token || constructor.name
        }, constructor);

        return constructor;
    };
}

/**
 * 参数注入装饰器
 * @param token 服务令牌
 */
export function Inject(token: ServiceToken) {
    return function (target: any, propertyKey: string | symbol | undefined, parameterIndex: number) {
        const existingTokens = Reflect.getMetadata(METADATA_KEYS.DEPENDENCIES, target) || [];
        existingTokens[parameterIndex] = token;
        Reflect.defineMetadata(METADATA_KEYS.DEPENDENCIES, existingTokens, target);
    };
}

/**
 * 属性注入装饰器
 * @param token 服务令牌
 */
export function InjectProperty(token: ServiceToken) {
    return function (target: any, propertyKey: string | symbol) {
        // 延迟注入，在实例化后注入属性
        const originalInit = target.init;
        target.init = function () {
            if (typeof this._container !== 'undefined') {
                this[propertyKey] = this._container.get(token);
            }
            if (originalInit) {
                originalInit.call(this);
            }
        };
    };
}

/**
 * 可选注入装饰器
 * @param token 服务令牌
 */
export function Optional(token: ServiceToken) {
    return function (target: any, propertyKey: string | symbol | undefined, parameterIndex: number) {
        const existingTokens = Reflect.getMetadata(METADATA_KEYS.DEPENDENCIES, target) || [];
        existingTokens[parameterIndex] = { token, optional: true };
        Reflect.defineMetadata(METADATA_KEYS.DEPENDENCIES, existingTokens, target);
    };
}

/**
 * 多实例注入装饰器
 * @param token 服务令牌
 */
export function InjectAll(token: ServiceToken) {
    return function (target: any, propertyKey: string | symbol | undefined, parameterIndex: number) {
        const existingTokens = Reflect.getMetadata(METADATA_KEYS.DEPENDENCIES, target) || [];
        existingTokens[parameterIndex] = { token, multiple: true };
        Reflect.defineMetadata(METADATA_KEYS.DEPENDENCIES, existingTokens, target);
    };
}

/**
 * 工厂方法装饰器
 */
export function Factory() {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        const originalMethod = descriptor.value;
        descriptor.value = function (...args: any[]) {
            // 工厂方法逻辑
            return originalMethod.apply(this, args);
        };
    };
}
